/**
 * 白名单
 */
use actix_web::{delete, post, web, Error, HttpResponse};
use chrono::Duration;
use chrono::Local;
use md5::Md5;
use md5::Digest;
use crate::ip_block;
use crate::ip_block::IpBlock;
use crate::model::recovery_list_model::*;
use crate::response;
use super::DbPool;
use crate::models::{self};
use crate::action;

/**
 * 分页查询
 */
#[post("/api/recovery-list/query/find-by-page")]
async fn find_by_page(
    pool: web::Data<DbPool>,
    form: web::Json<RecoveryListDTO>,
) -> Result<HttpResponse, Error> {
    // use web::block to offload blocking Diesel code without blocking server thread
    if form.current.is_none() || form.page_size.is_none() {
        let list_result: models::ListResult<RecoveryList> = models::ListResult {
            success: true,
            error_code: "".to_string(),
            error_message: "current或pageSize不能为空".to_string(),
            data: None,
            total: 0,
        };
        return Ok(HttpResponse::Ok().json(list_result));
    }
    let recovery_list_vec = web::block(move || {
        let conn = pool.get()?;
        action::recovery_list_action::find_by_page(form.current.unwrap(), form.page_size.unwrap(), &conn)
    })
    .await?
    .map_err(actix_web::error::ErrorInternalServerError)?;

    Ok(HttpResponse::Ok().json(models::ListResult {
        success: true,
        error_code: "".to_string(),
        error_message: "".to_string(),
        data: recovery_list_vec.0,
        total: recovery_list_vec.1,
    }))
}

/**
 * 按ID查询
 */
#[post("/api/recovery-list/query/find-by-id")]
async fn find_by_id(
    pool: web::Data<DbPool>,
    form: web::Json<RecoveryListDTO>,
) -> Result<HttpResponse, Error> {
    if form.id.is_none() {
        let sys_result: models::SysResult<RecoveryList> = models::SysResult {
            success: true,
            error_code: "".to_string(),
            error_message: "id不能为空".to_string(),
            data: None,
        };
        return Ok(HttpResponse::Ok().json(sys_result));
    }
    // use web::block to offload blocking Diesel code without blocking server thread
    let recovery_list = web::block(move || {
        let conn = pool.get()?;
        action::recovery_list_action::find_by_id(form.id.as_ref().unwrap(), &conn)
    })
    .await?
    .map_err(actix_web::error::ErrorInternalServerError)?;

    Ok(HttpResponse::Ok().json(models::SysResult {
        success: true,
        error_code: "".to_string(),
        error_message: "".to_string(),
        data: Some(recovery_list),
    }))
}

/**
 * 新增
 */
#[post("/api/recovery-list/insert")]
async fn insert(
    pool: web::Data<DbPool>,
    form: web::Json<RecoveryListDTO>,
) -> Result<HttpResponse, Error> {
    if form.recovery_type.is_none() || form.recovery_key.is_none() || form.mal_obj_type.is_none() || form.mal_obj_key.is_none() {
        let sys_result: models::SysResult<RecoveryList> = models::SysResult {
            success: true,
            error_code: "".to_string(),
            error_message: "recovery_type、recovery_key、mal_obj_type、mal_obj_key不能为空".to_string(),
            data: None,
        };
        return Ok(HttpResponse::Ok().json(sys_result));
    }
    // use web::block to offload blocking Diesel code without blocking server thread
    
    let recovery_list_vec = web::block(move || {
        let conn = pool.get()?;
        
        let mut hasher = Md5::new();
        hasher.update(form.mal_obj_type.as_ref().unwrap().as_bytes());
        hasher.update(form.mal_obj_key.as_ref().unwrap().as_bytes());
        let result = hasher.finalize();
        let id = format!("{:x}", result);

        let create_time = Local::now().timestamp_millis();
        let mut expire_time = Local::now().checked_add_signed(Duration::days(365)).unwrap().timestamp_millis();
        if form.expire_time.is_some() {
            expire_time = form.expire_time.unwrap();
        }

        action::recovery_list_action::insert(RecoveryList {
            id: id,
            mal_obj_key: form.mal_obj_key.as_ref().unwrap().to_string(),
            mal_obj_type: form.mal_obj_type.as_ref().unwrap().to_string(),
            recovery_type: form.recovery_type.as_ref().unwrap().to_string(),
            recovery_key: form.recovery_key.as_ref().unwrap().to_string(),
            recovery_value: form.recovery_value.as_ref().unwrap().to_string(),
            create_time: create_time,
            expire_time: expire_time,
            source: "user".to_string()
        }, &conn)
    })
    .await?
    .map_err(actix_web::error::ErrorInternalServerError)?;

    Ok(HttpResponse::Ok().json(models::SysResult {
        success: true,
        error_code: "".to_string(),
        error_message: "".to_string(),
        data: Some(recovery_list_vec),
    }))
}

/**
 * 删除
 */
#[delete("/api/recovery-list/delete")]
async fn delete(
    pool: web::Data<DbPool>,
    ip_block: web::Data<ip_block::Iptables>,
    form: web::Json<RecoveryListDTO>,
) -> Result<HttpResponse, Error> {
    if form.id.is_none() {
        let sys_result: models::SysResult<RecoveryList> = models::SysResult {
            success: true,
            error_code: "".to_string(),
            error_message: "id不能为空".to_string(),
            data: None,
        };
        return Ok(HttpResponse::Ok().json(sys_result));
    }
    // use web::block to offload blocking Diesel code without blocking server thread
    let alert_vec = web::block(move || {
        let conn = pool.get()?;
        let result = action::recovery_list_action::find_by_id(form.id.as_ref().unwrap(), &conn)?;
        match result {
            Some(recovery_list) => {
                // 解封IP
                if recovery_list.mal_obj_type == "IP" {
                    // 执行IP解封
                    ip_block.del(&recovery_list.mal_obj_key);
                    println!("解封IP");
                }
                // 恢复进程
                if recovery_list.mal_obj_type == "Process" {
                    let pid = recovery_list.mal_obj_key.parse::<i32>().unwrap();
                    response::process_suspend::resume(pid);
                    println!("恢复进程");
                }
                // 还原文件
                if recovery_list.mal_obj_type == "File" {
                    let recovery_value: RecoveryValue = serde_json::from_str(&recovery_list.recovery_value).unwrap();
                    response::file_isolate::recovery(&recovery_list.recovery_key, &recovery_list.mal_obj_key, recovery_value.mode.unwrap());
                    println!("还原文件");
                }
            },
            None => (),
        }
        action::recovery_list_action::delete_by_id(form.id.as_ref().unwrap(), &conn)
    })
    .await?
    .map_err(actix_web::error::ErrorInternalServerError)?;

    Ok(HttpResponse::Ok().json(models::SysResult {
        success: true,
        error_code: "".to_string(),
        error_message: "".to_string(),
        data: Some(alert_vec),
    }))
}